#pragma once
//#include <Ogre.h>
#include <OgreMovableObject.h>
#include <OgreResourceManager.h>
#include <vector>
#include <string>
#include <map>
#include "Bullet.h"
#include "Clip.h"
class CBarrage: public Ogre::MovableObject, public CClipManager {
    //------------------------------------------------------------------------------
    // Movable
public:
    CBarrage();
    ~CBarrage();
    virtual void _updateRenderQueue(Ogre::RenderQueue* queue);

    /** Overridden from MovableObject */
    virtual const std::string& getMovableType(void) const;

    /** Retrieves the local axis-aligned bounding box for this object.
    @remarks
    This bounding box is in local coordinates.
    */
    virtual const Ogre::AxisAlignedBox& getBoundingBox(void) const { return mAABB; }
    virtual Ogre::Real getBoundingRadius(void) const { return mBoundingRadius; }

    /// @copydoc MovableObject::visitRenderables
    virtual void visitRenderables(Ogre::Renderable::Visitor* visitor, 
        bool debugRenderables = false);

    //------------------------------------------------------------------------------
    // CBarrage (BulletSystem)
    CBullet* getBullet(int index);
    void setBulletQuota(int size);

    CBullet* createBullet(void);
    //class CClip* createClip(const std::string &name);

    //static const int maxClips = 10;
    void setParentPos(const Ogre::Vector3 &pos = Ogre::Vector3::ZERO) {
        mParentPos = pos;
    }
    //------------------------------------------------------------------------------
    void fastForward(Ogre::Real time, Ogre::Real interval = 0.1f);
    void configureRenderer(void);
    static Ogre::Real msDefaultIterationInterval;
    //static CBarrage* createBarrage(const std::string &name);
    //Ogre::SceneNode *getSceneNode() {
    //    return 
    //}
    //------------------------------------------------------------------------------
    // Renderer
public:
    void _updateRenderQueue(Ogre::RenderQueue* queue, 
        Ogre::list<CBullet*>::type& currentBullets);
    void _update(Ogre::Real timeElapsed);
    void increasePool(size_t size);
    void _expire(Ogre::Real timeElapsed);
    void _updateBounds();
    void _triggerEmitters(Ogre::Real timeElapsed);
    void _applyMotion(Ogre::Real timeElapsed);
    void setMaterialName(const std::string& name, const std::string& groupName  = Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME );
    size_t getNumBullets(void) const;
    void setNonVisibleUpdateTimeout(Ogre::Real timeout);
    void setIterationInterval(Ogre::Real interval);
    size_t getBulletQuota(void) const;
    void _notifyAttached(Ogre::Node* parent, bool isTagPoint);
    void setBounds(const Ogre::AxisAlignedBox& aabb);
    void setBillboardSetBounds(const Ogre::AxisAlignedBox& aabb);
    void _notifyCurrentCamera(Ogre::Camera* cam);
    //------------------------------------------------------------------------------
    // Emitter 

    //==============================================================================
    // CBarrage member
    typedef Ogre::list<CBullet*>::type ActiveBulletList;
    typedef Ogre::list<CBullet*>::type FreeBulletList;
    typedef Ogre::vector<CBullet*>::type BulletPool;

	/** Active particle list.
        @remarks
            This is a linked list of pointers to particles in the particle pool.
        @par
            This allows very fast insertions and deletions from anywhere in 
            the list to activate / deactivate particles as well as reuse of 
            CBullet instances in the pool without construction & destruction 
            which avoids memory thrashing.
    */
    ActiveBulletList mActiveBullets;
    /** Free particle queue.
        @remarks
            This contains a list of the particles free for use as new instances
            as required by the set. CBullet instances are preconstructed up 
            to the estimated size in the mBulletPool vector and are 
            referenced on this deque at startup. As they get used this list
            reduces, as they get released back to to the set they get added
			back to the list.
    */
    FreeBulletList mFreeBullets;

    /** Pool of particle instances for use and reuse in the active particle list.
        @remarks
            This vector will be preallocated with the estimated size of the set,and will extend as required.
    */
    BulletPool mBulletPool;
    /// The number of particles in the pool.
    size_t mPoolSize;

    /// Name of the resource group to use to load materials
    std::string mResourceGroupName;
    /// Name of the material to use
    std::string mMaterialName;
    /// Have we set the material etc on the renderer?
    bool mIsRendererConfigured;
    /// Pointer to the material to use
    Ogre::MaterialPtr mpMaterial;
    /// Default width of each particle
    Ogre::Real mDefaultWidth;
    /// Default height of each particle
    Ogre::Real mDefaultHeight;

    /// Bullets in local space?
    bool mLocalSpace;
    /// Speed factor
    Ogre::Real mSpeedFactor;
    /// Iteration interval
    Ogre::Real mIterationInterval;
    /// Iteration interval set? Otherwise track default
    bool mIterationIntervalSet;

    bool mBoundsAutoUpdate;
    Ogre::Real mBoundsUpdateTime;
    Ogre::Real mUpdateRemainTime;
    /// Used to control if the particle system should emit particles or not.
    bool mIsEmitting;
    /// Amount of time non-visible so far
    Ogre::Real mTimeSinceLastVisible;
    /// Last frame in which known to be visible
    unsigned long mLastVisibleFrame;
    //------------------------------------------------------------------------------
    // Movable member
private:

    Ogre::Real mBoundingRadius;
    Ogre::AxisAlignedBox mAABB;

    //------------------------------------------------------------------------------
    // Renderer member
private:

    Ogre::BillboardSet *mBillboardSet;

    //-------------------------------------------------------------------------------------
    // Game member
    Ogre::Vector3 mParentPos;
};
//
//class CBarrageFactory{
//public:
//    //CBarrageFactory(Ogre::SceneManager* sceneMgr): mSceneMgr(sceneMgr) {};
//    //~CBarrageFactory() {};
//    static CBarrage* createBarrage(std::string name, std::string templateName);
//};

class CBarrageFactory : public Ogre::MovableObjectFactory, public Ogre::Singleton<CBarrageFactory>{
protected:
    Ogre::MovableObject* createInstanceImpl(const std::string& name, const Ogre::NameValuePairList* params);

public:
    CBarrageFactory() {}
    ~CBarrageFactory() {}

    static std::string FACTORY_TYPE_NAME;

    const std::string& getType(void) const;
    void destroyInstance( Ogre::MovableObject* obj);  

public:
};